export class Polyline {
	constructor(viewer, iCesium) {
		this._viewer = viewer;
		this._iCesium = iCesium;
		this._dataSource = new iCesium.CustomDataSource('Polyline-data');
		this._viewer.dataSources.add(this._dataSource);
		this.decorates = new Map();
	}

	/**
	 * 添加标签
	 * @returns {boolean}
	 */
	async add(polylineData, callback) {
		const {
			id,
			polylineType = 0,
			coordinateType = 1,
			userData,
			fillColor,
			lineWidth,
			locationData,
			lineStyle = 0,
			...other
		} = polylineData;
		if (this.decorates.get(id)) return console.error('decorator already registered');

		let positions, linePoints;
		if (+coordinateType === 1) {
			const p = locationData.flat();
			if (Math.abs(p[0]) < Math.PI && Math.abs(p[1]) < Math.PI / 2) {
				positions = this._iCesium.Cartesian3.fromRadiansArrayHeights([...p]);
			} else {
				positions = this._iCesium.Cartesian3.fromDegreesArrayHeights([...p]);
			}
		} else {
			positions = locationData.map((point) => this._iCesium.Cartesian3.fromArray(point));
		}
		linePoints = [...positions];
		if (+polylineType === 1) {
			// 插值、增加控制点
			const pts = this.getBezierPoints(positions);
			const temp = [];
			// 计算贝塞尔曲线上的点
			pts.forEach((item) => {
				const aj = [];
				const dt = 1.0 / (40 - 1);
				for (let i = 1; i < 40; i++) {
					const a = this.CalculateBezierPointForCubic(i * dt, item[0], item[1], item[2], item[3]);
					aj.push(a);
				}
				temp.push(...aj);
			});
			linePoints = temp;
		}

		let material;
		const color = (color) => color && this._iCesium.Color.fromCssColorString(color);
		if (+lineStyle === 1) {
			material = new this._iCesium.PolylineDashMaterialProperty({ color: color(fillColor) });
		} else {
			material = color(fillColor);
		}

		other.depthFailMaterial =
			other.depthFailMaterial ||
			new this._iCesium.PolylineDashMaterialProperty({ color: color(fillColor) });

		this._callback = callback || undefined; // 回调函数

		const param = Object.assign(
			{
				positions: linePoints,
				width: lineWidth,
				material: material
			},
			other
		);

		const line = this._dataSource.entities.add({
			id,
			coordinateType,
			userData: userData,
			polyline: param
		});
		const point = positions.map((point) => {
			return this._dataSource.entities.add({
				position: point,
				point: {
					show: true,
					disableDepthTestDistance: Number.POSITIVE_INFINITY,
					pixelSize: polylineData.pointSize || 8,
					color: color(polylineData.pointColor)
				}
			});
		});

		this.decorates.set(id, { markerData: polylineData, line, point });

		callback && this.setHandler(callback);
	}

	setHandler(callback) {
		const viewer = this._viewer;
		if (!viewer.polylineHandler) {
			viewer.polylineHandler = new this._iCesium.ScreenSpaceEventHandler(viewer.scene.canvas);
		}

		viewer.polylineHandler.setInputAction((click) => {
			const pick = viewer.scene.pick(click.position);
			if (pick && typeof pick.id === 'object') {
				callback(this.decorates.get(pick.id.id.toString()));
			}
		}, this._iCesium.ScreenSpaceEventType.LEFT_CLICK);
	}

	/**
	 * 清空标签
	 * @returns {boolean}
	 */
	clear() {
		this._dataSource.entities.removeAll();
		this.decorates.clear();
		this._viewer.polylineHandler = null;
		return true;
	}

	/**
	 * 删除标签
	 * @returns {boolean}
	 */
	delete(id) {
		const marker = this.decorates.get(id);
		if (marker) {
			this._dataSource.entities.remove(marker.line);
			marker.point?.forEach((entity) => {
				this._dataSource.entities.remove(entity);
			});
			this.decorates.delete(id);
		}

		return true;
	}

	/**
	 * 获取标签
	 * @param {*} id
	 * @returns
	 */
	get(id) {
		return this._dataSource.entities.getById(id);
	}

	/**
	 * 更新标签
	 * @param id
	 * @param point
	 * @param markerData
	 * @returns {boolean}
	 */
	update(id, point, markerData) {}

	hide(ids) {}

	show(ids) {}

	hideAll() {}

	showAll() {}

	/**
	 * 三阶贝塞尔曲线
	 * B(t) = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3, t ∈ [0,1]
	 *
	 * @param t  曲线长度比例
	 * @param p0 起始点
	 * @param p1 控制点1
	 * @param p2 控制点2
	 * @param p3 终止点
	 * @return t对应的点
	 */
	CalculateBezierPointForCubic(t, p0, p1, p2, p3) {
		var point = new this._iCesium.Cartesian3();
		var temp = 1 - t;
		point.x =
			p0.x * temp * temp * temp +
			3 * p1.x * t * temp * temp +
			3 * p2.x * t * t * temp +
			p3.x * t * t * t;
		point.y =
			p0.y * temp * temp * temp +
			3 * p1.y * t * temp * temp +
			3 * p2.y * t * t * temp +
			p3.y * t * t * t;
		point.z =
			p0.z * temp * temp * temp +
			3 * p1.z * t * temp * temp +
			3 * p2.z * t * t * temp +
			p3.z * t * t * t;
		return point;
	}

	// 将点转换成贝塞尔点
	getBezierPoints(pts) {
		// const pointsArray = this._iCesium.Cartesian3.fromDegreesArrayHeights(pts)
		const pointsArray = pts;
		// 绘制路径
		const bezierPoints = [];
		let controlPoints = [];
		// 计算控制点数组
		if (pointsArray.length >= 3) {
			for (let i = 0; i < pointsArray.length - 2; i++) {
				const points = this.calculateControlPoint(
					pointsArray[i],
					pointsArray[i + 1],
					pointsArray[i + 2]
				);
				if (points) {
					console.log('calculateControlPoint', points);
					controlPoints = controlPoints.concat(points);
				}
			}
		}
		// 补足控制点数组前后端点， 便于计算
		controlPoints.unshift(pointsArray[0]);
		controlPoints.push(pointsArray[pointsArray.length - 1]);
		// 取控制点与节点生成多段bezier坐标数组
		for (let j = 0; j < pointsArray.length - 1; j++) {
			bezierPoints[j] = [
				pointsArray[j],
				controlPoints.shift(),
				controlPoints.shift(),
				pointsArray[j + 1]
			];
		}
		return bezierPoints;
	}

	calculateControlPoint(pt1, pt2, pt3) {
		const pointMid1 = {
			x: (pt1.x + pt2.x) / 2,
			y: (pt1.y + pt2.y) / 2,
			z: (pt1.z + pt2.z) / 2
		};
		const pointMid2 = {
			x: (pt2.x + pt3.x) / 2,
			y: (pt2.y + pt3.y) / 2,
			z: (pt2.z + pt3.z) / 2
		};

		const VecMid = new this._iCesium.Cartesian3(
			pointMid2.x - pointMid1.x,
			pointMid2.y - pointMid1.y,
			pointMid2.z - pointMid1.z
		);
		const VecFront = new this._iCesium.Cartesian3(
			pt2.x - pointMid1.x,
			pt2.y - pointMid1.y,
			pt2.z - pointMid1.z
		);
		const VecBack = new this._iCesium.Cartesian3(
			pointMid2.x - pt2.x,
			pointMid2.y - pt2.y,
			pointMid2.z - pt2.z
		);

		const FMdot = this._iCesium.Cartesian3.dot(VecFront, VecMid);
		// 长度
		const Mmag = this._iCesium.Cartesian3.magnitude(VecMid);

		const frontLength = Math.abs(FMdot / Mmag);

		const BMdot = this._iCesium.Cartesian3.dot(VecBack, VecMid);
		const backLength = Math.abs(BMdot / Mmag);

		const normalMid = new this._iCesium.Cartesian3();
		this._iCesium.Cartesian3.normalize(VecMid, normalMid);
		if (normalMid) {
			const front = new this._iCesium.Cartesian3();
			this._iCesium.Cartesian3.multiplyByScalar(normalMid, frontLength, front);
			const back = new this._iCesium.Cartesian3();
			this._iCesium.Cartesian3.multiplyByScalar(normalMid, backLength, back);
			const pt12 = new this._iCesium.Cartesian3(pt2.x - front.x, pt2.y - front.y, pt2.z - front.z);
			const pt23 = new this._iCesium.Cartesian3(pt2.x + back.x, pt2.y + back.y, pt2.z + back.z);

			return [pt12, pt23];
		}

		return [];
	}
}
